﻿using System;
using System.Collections.Generic;
using System.Reflection;

namespace Macds.Core.Mapping
{
    public static class MappingFactory
    {
        #region Mapping Attribute Creators

        /// <summary>
        /// This method convert any object decorated with the attribute Mapping to entity/class
        /// </summary>
        /// <typeparam name="T">the returned entity</typeparam>
        /// <param name="obj">the object</param>
        /// <returns>T</returns>
        public static T ConvertFromMappedToObject<T>(object obj) where T : new()
        {
            if (obj == null)
                return default(T);

            T newobj = new T();
            Type objType = obj.GetType();
            Type newType = newobj.GetType();

            var properties = objType.GetProperties();
            foreach (PropertyInfo pro in properties)
            {
                object[] attr = pro.GetCustomAttributes(typeof(MappingAttribute), false);
                
                if (attr != null)
                {
                    if (attr.Length == 1)
                    {
                        MappingAttribute map = (MappingAttribute)attr[0];
                        PropertyInfo newPro = newType.GetProperty(map.Name);
                        if (newPro == null)
                            throw new NullReferenceException(String.Format("The property {0} does not exists in the object of type {1}", map.Name, newType.ToString()));
                        newPro.SetValue(newobj, pro.GetValue(obj, null), null);
                    }
                }
            }

            return newobj;
        }

        /// <summary>
        /// This method convert any entity/class to object decorated with the attribute Mapping
        /// </summary>
        /// <typeparam name="T">the returned object</typeparam>
        /// <param name="obj">the entity</param>
        /// <returns>T</returns>
        public static T ConvertFromObjectToMapped<T>(object obj) where T : new()
        {
            if (obj == null)
                return default(T);

            T newobj = new T();
            Type objType = obj.GetType();
            Type newType = newobj.GetType();

            var properties = newType.GetProperties();
            foreach (PropertyInfo pro in properties)
            {
                object[] attr = pro.GetCustomAttributes(typeof(MappingAttribute), false);
                if (attr != null)
                {
                    if (attr.Length == 1)
                    {
                        MappingAttribute map = (MappingAttribute)attr[0];
                        PropertyInfo objPro = objType.GetProperty(map.Name);
                        if (objPro == null)
                            throw new NullReferenceException(String.Format("The property {0} does not exists in the object of type {1}", map.Name, objType.ToString()));
                        pro.SetValue(newobj, objPro.GetValue(obj, null), null);
                    }
                }
            }

            return newobj;
        }

        #endregion

        #region QueryString Attribute Creators

        public static string GetQueryStringFromObject(object obj)
        {
            string result = "";

            Dictionary<int, string> values = new Dictionary<int, string>();
            List<int> order = new List<int>();

            Type ObjectClass = obj.GetType();
            PropertyInfo[] properties = ObjectClass.GetProperties();

            foreach (PropertyInfo pInfo in properties)
            {
                object[] attributes = pInfo.GetCustomAttributes(typeof(QueryStringAttribute), true);
                if (attributes.Length == 1)
                {
                    QueryStringAttribute qs = (QueryStringAttribute)attributes[0];
                    bool can = true;
                    if (qs.optional)
                    {
                        if (pInfo.GetValue(obj, null) == null)
                        {
                            can = false;
                        }

                        if (can)
                        {
                            if (pInfo.GetValue(obj, null).ToString() == "")
                            {
                                can = false;
                            }
                        }
                    }

                    if (can)
                    {
                        if (pInfo.GetValue(obj, null) is DateTime)
                        {
                            DateTime tempDate = (DateTime)pInfo.GetValue(obj, null);
                            string strDate = String.Format("{0:dd.MM.yyyy}", tempDate);
                            values.Add(qs.position, qs.name + "=" + strDate);
                        }
                        else
                        {
                            values.Add(qs.position, qs.name + "=" + pInfo.GetValue(obj, null).ToString());
                        }

                        order.Add(qs.position);
                    }
                }
            }

            order.Sort();
            foreach (int position in order)
            {
                result += values[position] + "&";
            }

            result = result.Substring(0, result.Length - 1);
            return result;
        }

        #endregion
    }
}
